package com.tanhua.server.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.Question;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.dto.RecommendUserDto;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.vo.*;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.intercepter.UserThreadLocal;
import com.tanhua.server.service.MessagesService;
import com.tanhua.server.service.TanhuaService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RefreshScope
public class TanhuaServiceImpl implements TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MessagesService messagesService;

    @DubboReference
    private FriendApi friendApi;

    @DubboReference
    private UserLocationApi userLocationApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    //构造默认数据
    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

    //今日佳人
    @Override
    public TodayBest selectToDayBest() {
        //1.获取用户id
        Long userId = UserThreadLocal.getUserId();
        //调用api查询
        RecommendUser recommendUser = recommendUserApi.selectBest(userId);
        //判断对象是否为null
        if (recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }
        //3 将RecommendUser转化为TodayBest对象
        UserInfo info = userInfoApi.findById(recommendUser.getUserId());
        TodayBest vo = TodayBest.init(info, recommendUser);
        return vo;
    }

    //分页查询推荐好友列表
    @Override
    public PageResult recommendation(RecommendUserDto dto) {
        //1.获取用户id
        Long userId = UserThreadLocal.getUserId();
        //2、调用recommendUserApi分页查询数据列表（PageResult -- RecommendUser）
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);
        //3.获取分页的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();
        //4.判断列表是否为空
        if (items == null || items.size() <= 0) {
            return pr;
        }

        //5.提取所有推荐的用户id列表 (stream流操作)
        List<Long> ids = items.parallelStream()
                .map(RecommendUser::getUserId)
                .collect(Collectors.toList());

        //创建一个userInfo
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());
        //6.构建查询条件
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);
        //7、循环推荐的数据列表，构建vo对象
        List<TodayBest> list = items.parallelStream()
                .filter((s) -> {
                    return map.get(s.getUserId()) != null;
                })
                .map(item -> {
                    return TodayBest.init(map.get(item.getUserId()), item);
                }).collect(Collectors.toList());
        //8.构造返回值
        pr.setItems(list);
        return pr;
    }

    /**
     * 查看佳人信息
     *
     * @param bestId
     * @return
     */
    @Override
    public TodayBest findByBest(Long bestId) {
        //调用UserInfoApi
        UserInfo info = userInfoApi.findById(bestId);
        //根据操作人id和查看的用户id,查询两者推荐数据
        Long userId = UserThreadLocal.getUserId();
        RecommendUser user = recommendUserApi.queryByUserId(bestId, userId);

        //构造访客数据,调用Api保存
        Visitors visitors = new Visitors();
        visitors.setUserId(bestId);  //被访问
        visitors.setVisitorUserId(userId);  //用户访问
        visitors.setDate(System.currentTimeMillis());   //时间
        visitors.setScore(user.getScore());  //分数
        visitors.setFrom("今日佳人");  //来源
        visitors.setVisitDate(new SimpleDateFormat("yyyMMdd")
                .format(new Date()));  //日期
        //保存到访客表
        visitorsApi.save(visitors);

        //构造返回
        TodayBest init = TodayBest.init(info, user);
        return init;
    }


    /**
     * 查看陌生人的问题
     *
     * @param userId
     * @return
     */
    @Override
    public String findStrangerQuestions(Long userId) {

        Question question = questionApi.findByUserId(userId);
       /* if (question == null) {
            return "你喜欢java吗?";
        }
        return question.getTxt();*/
        return question == null ? "你喜欢篮球吗?" : question.getTxt();
    }

    /**
     * 回复陌生人的问题
     *
     * @param reply
     * @param userId
     */
    @Override
    public void replyQuestions(String reply, Long userId) {
        //1.构造返回的消息
        //1.1获取本用户id,并查询自己的详细信息
        Long localId = UserThreadLocal.getUserId();
        UserInfo info = userInfoApi.findById(localId);
        //1.2构造返回的对象
        ReplyVo vo = new ReplyVo();
        vo.setUserId(localId);
        vo.setHuanXinId("hx" + info.getId());
        vo.setNickname(info.getNickname());
        //调用方法:上面查看陌生人问题的方法传入陌生人的id
        vo.setStrangerQuestion(findStrangerQuestions(userId));
        vo.setReply(reply);
        //jason转字符串:返回消息
        String massage = JSON.toJSONString(vo);
        //2.调用huanXinTemplate发送回复消息
        Boolean aBoolean = huanXinTemplate.sendMsg("hx" + userId, massage);
        //3.判断是否成功
        if (!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    //查询探花-推荐用户列表
    @Override
    public List<TodayBest> cardsList() {
        Long userId = UserThreadLocal.getUserId();
        //1.调用api查询数据列表(排除不喜欢和喜欢过的用户,数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(userId, 10);
        //判断数据是否存在,不存在,构造默认数据
        if (CollUtil.isEmpty(users)) {
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String id : userIds) {
                RecommendUser user = new RecommendUser();
                user.setUserId(Convert.toLong(id));  //默认数据当中的推荐的id
                user.setToUserId(userId);    //推荐给当前用户的id
                user.setScore(RandomUtil.randomDouble(60, 90));  //构造分数60-90
                users.add(user);
            }
        }
        //3.构造vo返回数据
        //3.1提取推荐用户的id
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        //3.2 调用InfoApi查询ids的用户详情
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);

        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if (userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }

    //喜欢右滑
    @Override
    public void likeUser(Long likeUserId) {
        //1. 调用dubbo服务保存数据到MongoDB
        Long userId = UserThreadLocal.getUserId();
        Boolean save =
                userLikeApi.saveOrUpdate(userId, likeUserId, true);
        if (!save) {
            throw new BusinessException(ErrorResult.error());
        }
        //2. 保存喜欢数据到redis , 删除不喜欢数据  先删除,后保存
        redisTemplate.opsForSet().remove("USER_NOT_LIKE_KEY" + userId,
                likeUserId.toString());

        redisTemplate.opsForSet().add("USER_LIKE_KEY" + userId,
                likeUserId.toString());
        //3. 判断是否是双向喜欢, 如果是双向喜欢自动成为好友
        if (isLike(likeUserId, userId)) {
            //调用写过的 messagesService 添加好友方法
            messagesService.addFriend(likeUserId);
        }
    }

    /**
     * 抽取公共方法:判断是否双向喜欢
     * 供 -> 喜欢/不喜欢
     */
    public Boolean isLike(Long userId, Long likeUserId) {
        String key = "USER_LIKE_KEY" + userId;
        return redisTemplate.opsForSet().isMember(key, likeUserId.toString());
    }

    //左滑不喜欢
    @Override
    public void notLikeUser(Long likeUserId) {
        //1. 调用dubbo服务保存数据到MongoDB
        Long userId = UserThreadLocal.getUserId();
        Boolean save =
                userLikeApi.saveOrUpdate(userId, likeUserId, false);
        if (!save) {
            //失败
            throw new BusinessException(ErrorResult.error());
        }
        //2. 保存不喜欢数据到redis , 删除喜欢数据
        redisTemplate.opsForSet().add("USER_NOT_LIKE_KEY" + userId,
                likeUserId.toString());

        redisTemplate.opsForSet().remove("USER_LIKE_KEY" + userId,
                likeUserId.toString());

        //3. 判断是否是双向喜欢, 如果是双向喜欢取消好友关系
        // 探花系统好友关系,环信系统好友关系
        if (isLike(userId, likeUserId)) {
            //1.将好友关系从环信删除
            Boolean aBoolean = huanXinTemplate.deleteContact("hx" + userId, "hx" + likeUserId);
            if (!aBoolean) {
                throw new BusinessException(ErrorResult.error());
            }
            //2.成功,调用api从MongoDB中删除
            friendApi.deleteFriend(userId, likeUserId);
        }
    }


    //搜附近
    public List<NearUserVo> queryNearUser(String gender, String distance) {
        //1、调用API查询附近的用户（返回的是附近的人的所有用户id，包含当前用户的id）
        List<Long> userIds = userLocationApi.queryNearUser(UserThreadLocal.getUserId(), Double.valueOf(distance));
        //2、判断集合是否为空
        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        //3、调用UserInfoApi根据用户id查询用户详情
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, userInfo);
        //4、构造返回值。
        List<NearUserVo> vos = new ArrayList<>();
        for (Long userId : userIds) {
            //排除当前用户
            if (userId == UserThreadLocal.getUserId()) {
                continue;
            }
            UserInfo info = map.get(userId);
            if (info != null) {
                NearUserVo vo = NearUserVo.init(info);
                vos.add(vo);
            }
        }
        return vos;
    }
}